import json
import os
from datetime import datetime, date

from kivy.config import Config
from kivy.clock import Clock
from kivy.core.audio import SoundLoader

from config import FONTS_DIR, LEVEL_CONFIG, TEST_CASES, BUG_DESCRIPTIONS, SAVE_FILE, SOUNDS_DIR

# 设置全局默认字体 - 在导入其他模块之前设置
Config.set('kivy', 'default_font', [
    FONTS_DIR,  # 常规字体
    FONTS_DIR,  # 粗体
    FONTS_DIR,  # 斜体
    FONTS_DIR,  # 粗斜体
    FONTS_DIR  # 中文符号
])

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.properties import NumericProperty, StringProperty, BooleanProperty, ListProperty
import random


class SoundButton(Button):
    """带音效的按钮"""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.sound = None

    def load_sound(self, sound_file):
        """加载音效"""
        sound_path = os.path.join(SOUNDS_DIR, sound_file)
        if os.path.exists(sound_path):
            self.sound = SoundLoader.load(sound_path)
        else:
            print(f"⚠️ 音效文件不存在: {sound_file}")

    def on_press(self):
        """按钮按下时播放音效"""
        if hasattr(self, 'sound') and self.sound:
            self.sound.play()
        super().on_press()


class NMTesterGame(BoxLayout):
    # 游戏数据属性
    test_cases_executed = NumericProperty(0)  # 定义测试案例执行数
    bugs_found = NumericProperty(0)  # 定义缺陷发现数
    current_level = NumericProperty(1)  # 定义当前测试员等级 （初级-1 中级-2 高级-3 专家-4）
    level_name = StringProperty("初级测试工程师")
    current_test_case = StringProperty("准备执行测试...")
    # progress_text = StringProperty("下一等级: 0/5 缺陷")
    level_display = StringProperty("初级测试工程师 Lv.1")
    save_status = StringProperty("")  # 保存状态显示
    sound_enabled = BooleanProperty(True)  # 音效开关
    daily_executions = NumericProperty(0)  # 今日已执行次数
    daily_limit = NumericProperty(100)  # 每日限制次数
    daily_status = StringProperty("今日剩余: 100/100 次")  # 每日状态
    # 添加颜色属性
    daily_status_color = ListProperty([0.2, 0.6, 0.2, 1])  # 默认绿色
    execute_button_color = ListProperty([0.2, 0.6, 0.2, 1])  # 默认绿色

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.orientation = 'vertical'  # 设置布局方向为垂直 horizontal-水平 vertical-垂直
        self.padding = 20  # 设置内边距为20像素
        self.spacing = 15  # 设置子部件间距为15像素

        # 音效文件
        self.sounds = {}
        # 初始化游戏状态
        self.current_sub_level = 1
        self.bugs_in_current_level = 0
        if LEVEL_CONFIG[1]["bugs_needed"]:
            self.bugs_for_next_level = LEVEL_CONFIG[1]["bugs_needed"][0]
        else:
            self.bugs_for_next_level = 0

        # 历史记录
        self.bug_history = []  # 存储发现的缺陷历史
        self.level_history = []  # 存储等级提升历史
        self.game_start_time = datetime.now()
        self.last_play_date = date.today().isoformat()  # 最后游戏日期

        # 加载音效
        self.load_sounds()

        # 尝试加载保存的游戏数据
        self.load_game_data()
        # 检查日期重置
        self.check_date_reset()
        # 初始化显示文本
        self.update_display_texts()
        # 自动保存定时器（每30秒自动保存一次）
        Clock.schedule_interval(self.auto_save, 30)

    def check_date_reset(self):
        """检查是否需要重置每日次数"""
        today = date.today().isoformat()
        if self.last_play_date != today:
            # 新的一天，重置每日次数
            self.daily_executions = 0
            self.last_play_date = today
            self.save_status = "新的一天开始！次数已重置"
            print(f"✅ 日期变更，重置每日次数: {today}")
        else:
            print(f"ℹ️ 今日已执行: {self.daily_executions}/{self.daily_limit} 次")

    def load_sounds(self):
        """加载所有音效"""
        sound_files = {
            'button_click': 'button_click.wav',
            'bug_found': 'bug_found.wav',
            'level_up': 'level_up.wav'
        }

        for sound_name, sound_file in sound_files.items():
            sound_path = os.path.join(SOUNDS_DIR, sound_file)
            if os.path.exists(sound_path):
                self.sounds[sound_name] = SoundLoader.load(sound_path)
                print(f"✅ 加载音效: {sound_file}")
            else:
                print(f"⚠️ 音效文件不存在: {sound_file}")
                self.sounds[sound_name] = None

    def play_sound(self, sound_name):
        """播放指定音效"""
        if self.sound_enabled and sound_name in self.sounds and self.sounds[sound_name]:
            self.sounds[sound_name].play()

    def toggle_sound(self):
        """切换音效开关"""
        self.sound_enabled = not self.sound_enabled
        if self.sound_enabled:
            self.play_sound('button_click')
        return self.sound_enabled

    def auto_save(self, instance):
        """自动保存游戏数据"""
        self.save_game_data()
        self.save_status = f"自动保存: {datetime.now().strftime('%H:%M:%S')}"

    def get_save_data(self):
        """获取要保存的游戏数据"""
        return {
            # 基本游戏数据
            "test_cases_executed": self.test_cases_executed,
            "bugs_found": self.bugs_found,
            "current_level": self.current_level,
            "current_sub_level": self.current_sub_level,
            "bugs_in_current_level": self.bugs_in_current_level,
            "bugs_for_next_level": self.bugs_for_next_level,

            # 每日限制数据
            "daily_executions": self.daily_executions,
            "daily_limit": self.daily_limit,
            "last_play_date": self.last_play_date,

            # 历史记录
            "bug_history": self.bug_history[-50:],  # 只保存最近50条记录
            "level_history": self.level_history,
            "game_start_time": self.game_start_time.isoformat(),
            "last_save_time": datetime.now().isoformat(),
            "sound_enabled": self.sound_enabled,
            # 元数据
            "version": "1.0",
            "total_play_time": (datetime.now() - self.game_start_time).total_seconds()
        }

    def save_game_data(self):
        """保存游戏数据到文件"""
        try:
            save_data = self.get_save_data()
            with open(SAVE_FILE, 'w', encoding='utf-8') as f:
                json.dump(save_data, f, ensure_ascii=False, indent=2)
            print("✅ 游戏数据保存成功")
            return True
        except Exception as e:
            print(f"❌ 保存游戏数据失败: {e}")
            return False

    def load_game_data(self):
        """从文件加载游戏数据"""
        try:
            if os.path.exists(SAVE_FILE):
                with open(SAVE_FILE, 'r', encoding='utf-8') as f:
                    save_data = json.load(f)

                # 恢复基本游戏数据
                self.test_cases_executed = save_data.get("test_cases_executed", 0)
                self.bugs_found = save_data.get("bugs_found", 0)
                self.current_level = save_data.get("current_level", 1)
                self.current_sub_level = save_data.get("current_sub_level", 1)
                self.bugs_in_current_level = save_data.get("bugs_in_current_level", 0)
                self.bugs_for_next_level = save_data.get("bugs_for_next_level",
                                                         LEVEL_CONFIG[self.current_level]["bugs_needed"][0] if
                                                         LEVEL_CONFIG[self.current_level]["bugs_needed"] else 0)

                # 恢复每日限制数据
                self.daily_executions = save_data.get("daily_executions", 0)
                self.daily_limit = save_data.get("daily_limit", 100)
                self.last_play_date = save_data.get("last_play_date", date.today().isoformat())

                # 恢复历史记录
                self.bug_history = save_data.get("bug_history", [])
                self.level_history = save_data.get("level_history", [])

                # 恢复音效设置
                self.sound_enabled = save_data.get("sound_enabled", True)

                # 恢复等级名称
                self.level_name = LEVEL_CONFIG[self.current_level]["name"]

                print("✅ 游戏数据加载成功")
                self.save_status = f"已加载存档 ({len(self.bug_history)}条记录)"
            else:
                print("ℹ️ 无存档文件，开始新游戏")
                self.save_status = "新游戏"

        except Exception as e:
            print(f"❌ 加载游戏数据失败: {e}")
            self.save_status = "加载失败，开始新游戏"

    def update_display_texts(self):
        """更新所有显示文本"""
        # 更新等级显示
        if self.current_level == 4:
            self.level_display = "{}".format(self.level_name)
        else:
            self.level_display = "{} Lv.{}".format(self.level_name, self.current_sub_level)

        # 更新每日状态
        remaining = self.daily_limit - self.daily_executions
        if remaining <= 0:
            self.daily_status = "今日次数已用完"
        elif remaining <= 10:
            self.daily_status = f"今日剩余: {remaining}/{self.daily_limit} 次"
        else:
            self.daily_status = f"今日剩余: {remaining}/{self.daily_limit} 次"

        # 更新每日状态和颜色
        remaining = self.daily_limit - self.daily_executions
        if remaining <= 0:
            self.daily_status = "今日次数已用完"
            self.daily_status_color = [1, 0, 0, 1]  # 红色
            self.execute_button_color = [0.6, 0.6, 0.6, 1]  # 灰色
        elif remaining <= 10:
            self.daily_status = f"今日剩余: {remaining}/{self.daily_limit} 次"
            self.daily_status_color = [0.8, 0.5, 0, 1]  # 橙色
            self.execute_button_color = [0.2, 0.6, 0.2, 1]  # 绿色
        else:
            self.daily_status = f"今日剩余: {remaining}/{self.daily_limit} 次"
            self.daily_status_color = [0.2, 0.6, 0.2, 1]  # 绿色
            self.execute_button_color = [0.2, 0.6, 0.2, 1]  # 绿色
        # # 更新进度文本
        # if self.current_level == 4:
        #     self.progress_text = "已达成最高等级！"
        # else:
        #     self.progress_text = "下一等级: {}/{} 缺陷".format(
        #         self.bugs_in_current_level, self.bugs_for_next_level)

    def can_execute_test(self):
        """检查是否可以执行测试"""
        if self.daily_executions >= self.daily_limit:
            return False, "今日测试次数已用完！\n请明天再来。"
        return True, ""

    def execute_test_case(self):
        """执行测试案例"""
        self.play_sound('button_click')

        # 检查每日限制
        can_execute, message = self.can_execute_test()
        if not can_execute:
            self.show_limit_popup(message)
            return
        # 增加每日执行次数
        self.daily_executions += 1
        # 随机选择测试案例
        self.current_test_case = random.choice(TEST_CASES)
        self.test_cases_executed += 1

        # 30% 概率发现缺陷
        if random.random() < 0.3:
            self.find_bug()
        else:
            self.current_test_case += "\n测试通过，未发现缺陷"

        # 更新显示
        self.update_display_texts()
        # 自动保存
        self.save_game_data()

    def show_limit_popup(self, message):
        """显示限制弹窗"""
        content = BoxLayout(orientation='vertical', padding=10, spacing=10)
        content.add_widget(Label(
            text=message,
            font_size=20,
            color=(1, 0, 0, 1)
        ))

        # 显示今日统计
        stats_text = "今日统计:\n"
        stats_text += f"• 执行测试: {self.daily_executions} 次\n"
        stats_text += f"• 发现缺陷: {len([b for b in self.bug_history if b['time'].startswith(date.today().isoformat())])} 个"

        stats_label = Label(
            text=stats_text,
            font_size=16,
            color=(0.5, 0.5, 0.5, 1)
        )
        content.add_widget(stats_label)

        close_btn = Button(text='确定', size_hint_y=0.2)
        popup = Popup(title='每日限制', content=content, size_hint=(0.8, 0.5))

        def close_popup(instance):
            self.play_sound('button_click')
            popup.dismiss()

        close_btn.bind(on_press=close_popup)
        content.add_widget(close_btn)

        popup.open()

    def find_bug(self):
        """发现缺陷"""
        self.bugs_found += 1
        self.bugs_in_current_level += 1

        # 随机选择缺陷等级
        bug_levels = ["一般", "严重", "致命"]
        weights = [0.69, 0.30, 0.01]  # 概率权重
        bug_level = random.choices(bug_levels, weights=weights)[0]

        # 获取缺陷描述
        bug_description = random.choice(BUG_DESCRIPTIONS[bug_level])

        # 记录缺陷历史
        bug_record = {
            "time": datetime.now().isoformat(),
            "level": bug_level,
            "description": bug_description,
            "total_bugs": self.bugs_found
        }
        self.bug_history.append(bug_record)

        # 播放发现缺陷音效
        self.play_sound('bug_found')

        # 更新界面显示
        self.current_test_case += "\n发现{}缺陷: {}".format(bug_level, bug_description)

        # 更新显示文本
        self.update_display_texts()

        # 自动保存
        self.save_game_data()

        # 检查是否升级
        self.check_level_up()

    def check_level_up(self):
        """检查是否升级"""
        current_config = LEVEL_CONFIG[self.current_level]

        if self.current_level == 4:  # 测试专家是最高等级
            return

        if self.current_sub_level < current_config["max_level"]:
            # 检查子等级升级
            if self.bugs_in_current_level >= self.bugs_for_next_level:
                self.level_up()
        else:
            # 当前大等级已满，检查是否升级到下个大等级
            if self.bugs_in_current_level >= self.bugs_for_next_level:
                self.level_up()

    def level_up(self):
        """升级处理"""
        if self.current_level == 4:  # 已经是最高等级
            return
        # 对空列表的检查
        if LEVEL_CONFIG[self.current_level]["bugs_needed"]:
            self.bugs_for_next_level = LEVEL_CONFIG[self.current_level]["bugs_needed"][0]
        else:
            self.bugs_for_next_level = 0

        current_config = LEVEL_CONFIG[self.current_level]

        if self.current_sub_level < current_config["max_level"]:
            # 子等级提升
            old_level = f"{self.level_name} Lv.{self.current_sub_level}"
            self.current_sub_level += 1
            if self.current_sub_level <= len(current_config["bugs_needed"]):
                self.bugs_for_next_level = current_config["bugs_needed"][self.current_sub_level - 1]
            self.bugs_in_current_level = 0
            new_level = f"{current_config['name']} Lv.{self.current_sub_level}"
            # 记录等级历史
            self.record_level_up(old_level, new_level)
            # 播放升级音效
            self.play_sound('level_up')
            self.show_level_up_popup("恭喜！晋升为{} Lv.{}".format(
                current_config["name"], self.current_sub_level))
        else:
            # 大等级提升
            old_level = f"{self.level_name} Lv.{self.current_sub_level}"
            self.current_level += 1
            self.current_sub_level = 1
            self.level_name = LEVEL_CONFIG[self.current_level]["name"]
            self.bugs_in_current_level = 0
            if LEVEL_CONFIG[self.current_level]["bugs_needed"]:
                self.bugs_for_next_level = LEVEL_CONFIG[self.current_level]["bugs_needed"][0]
            else:
                self.bugs_for_next_level = 0
            new_level = f"{self.level_name} Lv.{self.current_sub_level}"

            # 记录等级历史
            self.record_level_up(old_level, new_level)
            # 播放升级音效
            self.play_sound('level_up')
            self.show_level_up_popup("重大晋升！成为{}！".format(self.level_name))

        # 更新显示文本
        self.update_display_texts()
        # 保存游戏
        self.save_game_data()

    def record_level_up(self, old_level, new_level):
        """记录等级提升历史"""
        level_record = {
            "time": datetime.now().isoformat(),
            "from": old_level,
            "to": new_level,
            "total_bugs": self.bugs_found,
            "total_tests": self.test_cases_executed
        }
        self.level_history.append(level_record)

    def show_level_up_popup(self, message):
        """显示升级弹窗"""
        content = BoxLayout(orientation='vertical', padding=10, spacing=10)
        content.add_widget(Label(text=message, font_size=24, color=(0, 0.7, 0, 1)))

        close_btn = Button(text='继续测试', size_hint_y=0.3)
        popup = Popup(title='升级通知', content=content, size_hint=(0.7, 0.4))
        close_btn.bind(on_press=popup.dismiss)
        content.add_widget(close_btn)

        popup.open()

    def show_history(self):
        """显示历史记录"""
        content = BoxLayout(orientation='vertical', padding=10, spacing=10)

        # 创建滚动视图
        from kivy.uix.scrollview import ScrollView
        from kivy.uix.gridlayout import GridLayout

        scroll = ScrollView()
        layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
        layout.bind(minimum_height=layout.setter('height'))

        # 添加标题
        title = Label(
            text=f"游戏历史记录\n总测试案例: {self.test_cases_executed}  总缺陷: {self.bugs_found}",
            font_size=20,
            size_hint_y=None,
            height=80
        )
        layout.add_widget(title)

        # 添加等级历史
        if self.level_history:
            level_title = Label(
                text="等级提升历史:",
                font_size=16,
                bold=True,
                size_hint_y=None,
                height=40
            )
            layout.add_widget(level_title)

            for record in self.level_history[-10:]:  # 显示最近10次升级
                level_text = "{} → {} (缺陷: {})".format(
                    record["from"], record["to"], record["total_bugs"]
                )
                level_label = Label(
                    text=level_text,
                    font_size=14,
                    size_hint_y=None,
                    height=30
                )
                layout.add_widget(level_label)

        # 添加最近缺陷记录
        if self.bug_history:
            bug_title = Label(
                text="最近发现的缺陷:",
                font_size=16,
                bold=True,
                size_hint_y=None,
                height=40
            )
            layout.add_widget(bug_title)

            for record in self.bug_history[-10:]:  # 显示最近10个缺陷
                bug_text = "{}: {}".format(record["level"], record["description"])
                bug_label = Label(
                    text=bug_text,
                    font_size=12,
                    size_hint_y=None,
                    height=25
                )
                layout.add_widget(bug_label)

        scroll.add_widget(layout)
        content.add_widget(scroll)

        close_btn = Button(text='关闭', size_hint_y=0.1)
        popup = Popup(title='游戏历史记录', content=content, size_hint=(0.9, 0.8))
        close_btn.bind(on_press=popup.dismiss)
        content.add_widget(close_btn)

        popup.open()

    def manual_save(self):
        """手动保存游戏"""
        if self.save_game_data():
            self.save_status = f"手动保存成功: {datetime.now().strftime('%H:%M:%S')}"
        else:
            self.save_status = "保存失败"

    def reset_game(self):
        """重置游戏"""
        content = BoxLayout(orientation='vertical', padding=10, spacing=10)
        content.add_widget(Label(
            text="确定要重置游戏吗？\n所有进度将被清空！",
            font_size=20,
            color=(1, 0, 0, 1)
        ))

        btn_layout = BoxLayout(orientation='horizontal', spacing=10, size_hint_y=0.3)
        confirm_btn = Button(text='确定重置')
        cancel_btn = Button(text='取消')

        popup = Popup(title='重置游戏', content=content, size_hint=(0.7, 0.4))

        def do_reset(instance):
            # 重置游戏数据
            self.test_cases_executed = 0
            self.bugs_found = 0
            self.current_level = 1
            self.current_sub_level = 1
            self.bugs_in_current_level = 0
            self.bugs_for_next_level = LEVEL_CONFIG[1]["bugs_needed"][0]
            self.level_name = "初级测试工程师"
            self.bug_history = []
            self.level_history = []
            self.daily_executions = 0
            self.game_start_time = datetime.now()

            # 删除存档文件
            if os.path.exists(SAVE_FILE):
                os.remove(SAVE_FILE)

            self.update_display_texts()
            self.save_status = "游戏已重置"
            popup.dismiss()

        confirm_btn.bind(on_press=do_reset)
        cancel_btn.bind(on_press=popup.dismiss)

        btn_layout.add_widget(confirm_btn)
        btn_layout.add_widget(cancel_btn)
        content.add_widget(btn_layout)

        popup.open()


class NMTesterApp(App):
    def build(self):
        self.title = "NMtester"
        return NMTesterGame()


if __name__ == '__main__':
    NMTesterApp().run()
